package db

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type Table struct {
	Name           string
	ActualName     string
	ColName2Type   map[string]string
	ColNameInorder []string
	CreateStmt     string
	InsertStmt     string
}

// 初始化数据库表,读取 .sql 文件逐个表创建
func InitTables(sqlpath string) {
	AnalyzeTables(sqlpath)
	CreateTables()
}

func AnalyzeTables(sqlpath string) {
	file, err := os.Open(sqlpath)
	if err != nil {
		logger.Fatal("[AnalyzeTables]: %v", err)
	}
	defer file.Close()
	reader := bufio.NewReader(file)

	var alllines []string
	var tb *Table
	var insertCol []string
	var insertPlaceholder []string
	for {
		lineBytes, _, err := reader.ReadLine()
		if lineBytes != nil && err == nil {
			line := string(lineBytes)
			line = strings.TrimSpace(line)
			if len(line) > 0 {
				if strings.HasPrefix(line, "#") { //过滤注释行
					continue
				}

				if strings.HasPrefix(line, "create table") { //建表语句开始
					firstLine := strings.Split(line, " ")
					nameidx := len(firstLine) - 1
					tbname := firstLine[nameidx]
					tbname = strings.ToLower(tbname) //表名转换成小写
					_, ok := g_dbworker.Tables[tbname]
					if ok {
						panic("table name exists:" + tbname)
					}
					tb = &Table{
						Name:           tbname,
						ActualName:     fmt.Sprintf("%s.%s", g_dbworker.DBName, tbname), //再将表名由 dbname 换成 dbname.tbname
						ColName2Type:   make(map[string]string),
						ColNameInorder: make([]string, 0),
						CreateStmt:     "",
					}
					firstLine[nameidx] = tb.ActualName
					line = strings.Join(firstLine, " ")

					alllines = make([]string, 0)
					insertCol = make([]string, 0)
					insertPlaceholder = make([]string, 0)

					alllines = append(alllines, line)
					continue
				}
				alllines = append(alllines, line)

				if strings.HasPrefix(line, "(") || strings.HasPrefix(line, ")ENGINE") || strings.HasPrefix(line, "PARTITION") || strings.HasPrefix(line, "PRIMARY") {
					continue
				} else if strings.HasPrefix(line, ");") { //语句结束
					//建表语句
					tb.CreateStmt = strings.Join(alllines, "")
					//插入语句: INSERT INTO user (name, age) VALUES (?, ?)
					tb.InsertStmt = fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",
						tb.ActualName, strings.Join(insertCol, ","), strings.Join(insertPlaceholder, ","))

					g_dbworker.Tables[tb.Name] = tb

					tb = nil
					alllines = nil
					insertCol = nil
					insertPlaceholder = nil
					continue
				} else { //每个字段类型解析, 只需要分析前两个
					varline := strings.Split(line, " ")
					colName := varline[0]
					colName = strings.TrimSpace(colName)
					colType := varline[1]
					//分析类型
					colType = strings.Split(colType, ",")[0] //省去右边的","
					colType = strings.Split(colType, "(")[0] //省去右边的"(xxx)" 类型长度
					colType = strings.TrimSpace(colType)
					//暂时仅支持这几种类型
					if !(colType == "int" || colType == "bigint" || colType == "double" || colType == "varchar" || colType == "DATETIME") {
						panic("colType error:" + colName + ":" + colType)
					}

					if colName != "inc_id" { //自增字段不用填
						tb.ColName2Type[colName] = colType
						tb.ColNameInorder = append(tb.ColNameInorder, colName)
						insertCol = append(insertCol, colName)

						if colType == "int" || colType == "bigint" {
							insertPlaceholder = append(insertPlaceholder, "%s")
						} else if colType == "varchar" || colType == "DATETIME" {
							insertPlaceholder = append(insertPlaceholder, "\"%s\"")
						} else if colType == "double" {
							insertPlaceholder = append(insertPlaceholder, "%s")
						}
					}
				}
			}
		}
		if err != nil {
			if err == io.EOF {
				break
			}
			logger.Fatal("[AnalyzeTables]: %v", err)
		}
	}
}

func CreateTables() {
	for tbname, v := range g_dbworker.Tables {
		stmt, err := g_dbworker.DB.Prepare(v.CreateStmt)
		if err != nil {
			logger.Fatal("[CreateTables]: tbname=%s,error=%v", tbname, err)
		}
		defer stmt.Close()

		_, err1 := stmt.Exec()
		if err1 != nil {
			logger.Fatal("[CreateTables]: tbname=%s,error=%v", tbname, err1)
		}
		logger.Info("[CreateTables]: ok.")
	}

	fmt.Println("initialize db tables ..")
}

func Insert(work string) {
	ret, str := AnalyzeWork(work) // 解析操作
	if !ret {
		logger.Info("[Insert]: fail, work=%s", work)
		fmt.Println(work)
		return
	}
	if !ExecStr(str) {
		fmt.Println("[Insert]: failed: ", str)
	}
}

func AnalyzeWork(work string) (bool, string) {
	// 解析操作
	return true, work
}
